package crossover;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;

import model.Chromosome;

public class PMX extends Crossover {
	Random rand = new Random();

	public PMX(double crossoverRate) {
		this.crossoverRate = crossoverRate;
	}
	@Override
	public Chromosome[] crossover(Chromosome[] parents) {
		int size = parents[0].getChromosome().size();
		double rate = rand.nextDouble() * 100;
		int index1 = rand.nextInt(size);
		int index2 = rand.nextInt(size);
		// swap
		if (index1 > index2) {
			int index3 = index1;
			index1 = index2;
			index2 = index3;

		}
		if (rate > crossoverRate) {

			ArrayList<Integer> ch1 = new ArrayList<Integer>(), ch2 = new ArrayList<Integer>();
			HashMap<Integer, Integer> map1= new HashMap<Integer, Integer>(size * 2);
			HashMap<Integer, Integer> map2= new HashMap<Integer, Integer>(size * 2);
			ArrayList<Integer> tmp1 = new ArrayList<Integer>(), tmp2 = new ArrayList<Integer>();
			for(int i=index1;i<index2;i++){
				tmp1.add(parents[0].getChromosome().get(i));
				tmp2.add(parents[1].getChromosome().get(i));
			}
			
			for (int i=0;i<size;i++) {
				map1.put(i, i);
				map2.put(i, i);
			}
			for(int i=index1;i<index2;i++){
				map2.put(parents[1].getChromosome().get(i), parents[0].getChromosome().get(i));
				map1.put(parents[0].getChromosome().get(i), parents[1].getChromosome().get(i));
			}
			for(int i=0;i<size;i++){
				if(index1<=i && i<index2){
					ch1.add(parents[0].getChromosome().get(i));
					ch2.add(parents[1].getChromosome().get(i));
				}
				else{
					int get=parents[1].getChromosome().get(i);
					int per1=map1.get(get);
					while(existNumInCh(tmp1,per1))
						per1=map1.get(per1);
					
					ch1.add(per1);
					
					get=parents[0].getChromosome().get(i);
					int per2=map2.get(get);
						while(existNumInCh(tmp2,per2))
							per2=map2.get(per2);
					ch2.add(per2);
//					checkChromosome(ch1);
//					checkChromosome(ch2);
				}
				
				
				
			}
			
			
			
			
			
//			for (int i = index1; i < index2; ++i) {
//				ch1.add(parents[0].getChromosome().get(i));
//				ch2.add(parents[1].getChromosome().get(i));
//			}
//			ArrayList<Integer> removed1 = removeExist(
//					parents[1].getChromosome(), ch1);
//			ArrayList<Integer> removed2 = removeExist(
//					parents[0].getChromosome(), ch2);
//			int j = 0;
//			for (int i = index2; i < size; i++, j++) {
//				ch1.add(removed1.get(j));
//				ch2.add(removed2.get(j));
//			}
//			
//			for(int i=0;i<index1;i++,j++){
//				ch1.add(0,removed1.get(j));
//				ch2.add(0,removed2.get(j));
//				
//			}
			 Chromosome chromosome1=new Chromosome(ch1);
			 Chromosome chromosome2=new Chromosome(ch2);
//			 System.out.println(parents[0].getChromosome());
//			 System.out.println(parents[1].getChromosome());
//			 System.out.println(index1+","+index2);
//			 System.out.println(ch1);
//			 System.out.println(ch2);
//			 System.out.println("________________________________________");
			 
			 
			 
			 if(chromosome1.getFitness()==0 || chromosome2.getFitness()==0)
				 System.out.println();
			Chromosome[] child = { chromosome1, chromosome2 };
			return child;
		} else
			return parents;
	}
	
	@Override
	public String toString() {
		return "PMX";
	}

	protected boolean existNumInCh(ArrayList<Integer> ch2, int num) {
		for (Integer integer : ch2) {
			if (integer.intValue() == num)
				return true;
		}
		return false;
	}

	protected ArrayList<Integer> removeExist(ArrayList<Integer> parent,
			ArrayList<Integer> exist) {
		// parent\exist=removed
		ArrayList<Integer> removed = new ArrayList<Integer>();
		for (Integer integer : parent) {
			if (!existNumInCh(exist, integer))
				removed.add(integer);

		}
		return removed;
	}
	void checkChromosome(ArrayList<Integer> ch1){
		int [] count={0,0,0,0,0};
		for (Integer i : ch1) {
			if(count[i]==0)
				count[i]++;
			else
				System.out.println("bad");
		}
		
		
	}

}
